# -*- coding: utf-8 -*-
# File : inventory_discovery.py
# Author: taoyahui
# Date : 2021/3/23
import sys
sys.path.append('..')
from utils import mysql_util, common_util,log_util
import nmap3
import json
import re
import logging
from utils import mongo_util
import time


# 通过inventory_discovery 配置库获取配置信息
def inventory_discovery():
    """
    通过inventory_discovery 配置库获取配置信息
    :return:
    """
    logger = common_util.get_logger("inventory_discovery")
    logger.info(f"Start to discover inventory under the Rules!")
    sql = f'select content, time_interval, is_availability from inventory_discovery'
    try:
        result = mysql_util.exec_sql_new(sql)
        ips = get_active_host_ip(result[0][0])
        save_new_inventory(ips)
        get_host_system(ips)
        save_inventory_discovery_log()
    except Exception as e:
        print(e)
    return 'ok'


def save_inventory_discovery_log():
    timestamp = int(time.time())
    res = {
        'timestamp': timestamp,
        'log': 'Execute inventory discovery service!'
    }
    mongo_util.insert_one_document('patch_distribute', 'inventory_discovery_log', res)


# 通过IP内容获取在线IP内容
def get_active_host_ip(content):
    content_dict = json.loads(content)
    ips = []
    try:
        ip_type_dict = content_dict['ip']
        for ip_content in ip_type_dict:
            type = ip_content['type']
            if type == 1 or type == 2:
                query_ip = ip_content['value']
            elif type == 3:
                pass
            ips.extend(nmap_util(ip_content['value']))
        log_util.logger.info(f"Find Intentory are :{ips}")
        return ips
    except Exception as e:
        logging.error(e)


# 扫描主机的操作系统类型
# 参数：
#     ips: 列表形式的IP地址，可以是getActiveHostIP()的返回值
# 返回值：
#     字典，键为IP地址，值为操作系统类型，未扫描到的为 未知
#     这个方法只能扫描到大致的操作系统类型，准确的Linux发行版可通过Ansible获取，该方法非常耗时！
def get_host_system(ips):

    os_detection = nmap3.Nmap()
    for ip in ips:
        oss = os_detection.nmap_os_detection(ip, args="-O")
        if oss.__contains__('error'):
            continue
        print(oss[ip])
        nmap_hostname = oss[ip]['hostname']
        nmap_macaddress = oss[ip]['macaddress']
        update_hostname_mac(nmap_hostname, nmap_macaddress, ip)
        # 更新系统的mac地址和hostname
        # 更新资产的系统变量
        get_inventory_os_sql = f"select ip, os from inventory where ip = '{ip}'"
        result = mysql_util.exec_sql_new(get_inventory_os_sql)
        if result[0][1] == '未知':
            print(oss)
            if not oss.__contains__('error'):
                osmatch = oss[ip]['osmatch']
                # print(osmatch)
                if len(osmatch) > 0:
                    update_inventory_os_sql = f"Update inventory set os = '{osmatch[0]['osclass']['osfamily'][0:30]}' where ip = '{ip}'"
                    # print(update_inventory_os_sql)
                    mysql_util.exec_sql_new(update_inventory_os_sql)


# 保存新的资产IP为已知，操作系统：未知
def save_new_inventory(ips):
    find_all_inventory_sql = 'select ip from inventory'
    try:
        exist_ips = [item[0] for item in mysql_util.exec_sql_new(find_all_inventory_sql)]
        d_set_ips = list(set(list(ips)).difference(set(exist_ips)))
        for ip in d_set_ips:
            # 插入资产表（ip， 系统， 未配置）
            insert_sql = f'INSERT INTO inventory(ip, os, is_available) VALUES ("{ip}", "未知", 2)'
            # print(insert_sql)
            mysql_util.exec_sql_new(insert_sql)
    except Exception as e:
        print(e)


# 保存host信息到inventory表中
def save_host(host_system_dict):

    find_all_inventory_sql = 'select ip from inventory'
    try:
        exist_ips = [item[0] for item in mysql_util.exec_sql_new(find_all_inventory_sql)]
        # 取已存在ip和检测ip的差集(在检测的IP池中， 不在已有的IP池中)
        d_set_ips = list(set(list(host_system_dict.keys())).difference(set(exist_ips)))
        for ip in d_set_ips:
            os_version = host_system_dict[ip]
            insert_sql = f'INSERT INTO inventory(ip, os) VALUES ("{ip}", "{os_version}")'
            print(insert_sql)
            mysql_util.exec_sql_new(insert_sql)
    except Exception as e:
        print(e)


# 使用nmap扫描获取ip信息
def nmap_util(ip_content=''):
    """
    使用nmap扫描获取ip信息
    :param ip_content:
    :return:
    """
    pattern = re.compile("(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])")
    nmap = nmap3.NmapHostDiscovery()
    result = nmap.nmap_no_portscan(ip_content)
    ips = [ip.strip() for ip in result if pattern.match(ip)]
    return ips


def update_hostname_mac(nmap_hostname=None, nmap_macaddress=None, ip="localhost"):
    """
    生成更新hostname和macaddress的更新sql，并更新
    :param nmap_hostname:
    :param nmap_macaddress:
    :param ip:
    :return:
    """
    update_dict = {}
    if len(nmap_hostname) > 0:
        name = nmap_hostname[0]['name']
        update_dict['hostname'] = name
    if nmap_macaddress is not None:
        mac = nmap_macaddress['addr']
        update_dict['mac'] = mac
    # print(update_dict)
    if nmap_hostname is None and nmap_macaddress is None:
        return

    update_content_sql = ""
    if len(update_dict.keys()) > 0:
        for key in update_dict.keys():
            update_content_sql += f"{key}='{update_dict[key]}',"
        update_sql = f"Update inventory set {update_content_sql[:-1]} where ip = '{ip}'"
        print(update_sql)
        mysql_util.exec_sql_new(update_sql)


if __name__ == '__main__':
    # content = '{"ip":[{"type":1,"value": "192.168.50.1/24"}]}'
    # inventory_discovery()
    # update_hostname_mac(ip="192.168.1.10")
    ips = ['192.168.50.156']
    save_new_inventory(ips)
